_dss_editor._model.link = {};
_link = _dss_editor._model.link;
_link.getAnchorPoint = function(diagram, angle) {
    if (diagram.style === LINK) {
        return this.getAnchorByLink(diagram);
    } else {
        return this.getAnchorBySystem(diagram, angle);
    }
};
_link.getAnchorByLink = function(link) {
    var fromPoint = _dss_editor._model.link.getAnchorPoint(link.getFromSystem(), link.showInfo.fromAngle);
    var toPoint = _dss_editor._model.link.getAnchorPoint(link.getToSystem(), link.showInfo.toAngle);
    return {
        x : (fromPoint.x + toPoint.x) / 2,
        y : (fromPoint.y + toPoint.y) / 2
    };
};
_link.getAnchorBySystem = function(system, angle) {
    var center = {
        x : 0,
        y : 0
    };
    var point = {
        x : 0,
        y : 0
    };
    var bounds = _dss_editor._toolkit.translateToAbsolute(system);
    if (system.isShowLabel() && system.isShowContent()) {
        bounds.y += labelHeight;
        bounds.h -= labelHeight;
    }
    var h = bounds.h;
    var w = bounds.w;
    var halfH = h / 2;
    var halfW = w / 2;
    center.x = bounds.x + halfW;
    center.y = bounds.y + halfH;

    var tang = Math.atan2(h, w);

    if (angle < 0) {
        angle += Math.PI * 2;
    }
    if (angle >= Math.PI * 2 - tang || angle <= tang) {
        point.x = w + bounds.x;
        point.y = center.y + halfW * Math.tan(angle);
    } else if (angle >= tang && angle <= Math.PI - tang) {
        point.y = bounds.y + bounds.h;
        point.x = bounds.x + +halfW + halfH / Math.tan(angle);
    } else if (angle <= Math.PI + tang && angle >= Math.PI - tang) {
        point.x = bounds.x;
        point.y = center.y + halfW * Math.tan(angle);
    } else {
        point.y = bounds.y;
        point.x = bounds.x + +halfW + halfH / Math.tan(angle);
    }

    point.y = parseInt(point.y);
    point.x = parseInt(point.x);

    return point;
};
_link.genAngle = function(diagram, point) {
    var center = {
        x : 0,
        y : 0
    };
    if (diagram.style === LINK) {
        return 0;
    }
    var bounds = _dss_editor._toolkit.translateToAbsolute(diagram);
    var h = bounds.h;
    var w = bounds.w;
    var y = bounds.y;
    if (diagram.style == SYSTEM && diagram.isShowLabel() && diagram.isShowContent()) {
        h -= labelHeight;
        y += labelHeight;
    }
    var halfH = h / 2;
    var halfW = w / 2;
    center.x = bounds.x + halfW;
    center.y = y + halfH;
    var angle = 0;
    var len = Math.sqrt((point.x - center.x) * (point.x - center.x) + (point.y - center.y) * (point.y - center.y));

    if (point.x == bounds.x) {
        angle = Math.acos(halfW / len);
        if (point.y >= center.y) {
            angle = Math.PI + angle;
        } else if (point.y < center.y) {
            angle = Math.PI - angle;
        }
    } else if (point.y == center.y - halfH) {
        angle = Math.acos(halfH / len);
        if (point.x > center.x) {
            angle = Math.PI * 3 / 2 - angle;
        } else if (point.x <= center.x) {
            angle += Math.PI * 3 / 2;
        }
    } else if (point.x == bounds.x + bounds.w) {
        angle = Math.acos(halfW / len);
        if (point.y < center.y) {
            angle = Math.PI * 2 - angle;
        }
    } else if (point.y == center.y + halfH) {
        angle = Math.acos(halfH / len);
        if (point.x > center.x) {
            angle = Math.PI / 2 - angle;
        } else if (point.x <= center.x) {
            angle += Math.PI / 2;
        }
    }
    return angle;
};

// 参数nodes 是所有首层的节点
_link.initLinks = function(canvas) {
    //var links = canvas.sysForView.complete.links;
    if (canvas.sysForView.complete.hasOwnProperty('links')) {
        canvas.links = canvas.sysForView.complete.links;
        var diagrams = canvas.sys.getChildren();
        var branchLinks = [];
        for (var j = 0; j < canvas.links.length; j++) {
            if (_dss_editor._toolkit.findLinkByName(canvas.links, canvas.links[j].from)) {
                branchLinks.push(canvas.links[j]);
            } else {
                this.initLink({
                    canvas : canvas,
                    link : canvas.links[j]
                });
            }
        }
        //暂时这样处理
        for (var j = 0; j < branchLinks.length; j++) {
            this.initLink({
                canvas : canvas,
                link : branchLinks[j]
            });
        }
    }
};

// 该方法主要用于 from或者 to的parent在进行折叠操作的时候或者drill down操作的时候，连线的不同的状态
// 如果连线的from和to 同时所在的parent折叠之后，那么该连线隐藏
// 如果不同的parent或者只有其中一个parent折叠，那么需要设置该连线的physic
_link.updateStatus = function() {
    this.physicFromSystem = null;
    this.physicToSystem = null;
    this.showInfo.visible = 'yes,no;yes';

    if (this.toSystem == null || this.fromSystem == null) {
        console.error('to:' + this.to + ';from:' + this.from);
        return;
    }
    var toParent = this.toSystem.parent;
    var fromParent;
    if (this.fromSystem.fromSystem) {
        fromParent = this.fromSystem.fromSystem.parent;
    } else {
        fromParent = this.fromSystem.parent;
    }
    while (toParent) {
        if (toParent.parent && toParent.isShowContent && !toParent.isShowContent()) {
            this.physicToSystem = toParent;
            if (toParent == this.fromSystem) {
                this.showInfo.visible = 'yes,no;no';
                return;
            }
        }
        toParent = toParent.parent;
    }

    while (fromParent) {
        if (fromParent.parent && fromParent.isShowContent && !fromParent.isShowContent()) {
            this.physicFromSystem = fromParent;
            if (fromParent == this.toSystem) {
                this.showInfo.visible = 'yes,no;no';
                return;
            }
        }
        fromParent = fromParent.parent;
    }

    if (this.physicFromSystem != null) {
        var parent = this.physicFromSystem.parent;
        while (parent) {
            if (parent == this.physicToSystem) {
                this.showInfo.visible = 'yes,no;no';
                break;
            }
            parent = parent.parent;
        }
    }
    if (this.physicToSystem != null) {
        var parent = this.physicToSystem.parent;
        while (parent) {
            if (parent == this.physicFromSystem) {
                this.showInfo.visible = 'yes,no;no';
                break;
            }
            parent = parent.parent;
        }
    }
    if (this.physicFromSystem == this.physicToSystem && this.physicToSystem != null) {
        this.showInfo.visible = 'yes,no;no';
        //如果2个physic system相同，则说明该连线在该同一个system下面，则不用设置该属性，清空
        this.physicFromSystem = null;
        this.physicToSystem = null;
    }
};

/*
 * 主要是计算锚点和拐点的位置
 */
_link.layout = function() {
     // 关于自迁移
    if (this.fromSystem && this.toSystem && this.fromSystem == this.toSystem) {
        this.showInfo.fromAngle = Math.PI * 3 / 4;
        this.showInfo.toAngle = Math.PI / 4;
        var fromPoint = _dss_editor._model.link.getAnchorPoint(this.fromSystem, this.showInfo.fromAngle);
        var toPoint = _dss_editor._model.link.getAnchorPoint(this.toSystem, this.showInfo.toAngle);
        var bendPoint = function() {
            var fromPoint = arguments[0];
            var toPoint = arguments[1];
            return {
                x : (fromPoint.x + toPoint.x) / 2,
                y : fromPoint.y + 20
            };
        };
        this.bendPoints.push(bendPoint);
    }
};
_link.initLink = function() {
    //	link.type = type;
    var args = arguments[0];
    var that = this;
    var canvas = args.canvas;
    var diagrams = args.diagrams;
    var links = args.links;
    var link = args.link;
    if (canvas) {
        diagrams = canvas.baseSysForView.complete.sys.getChildren();
        links = canvas.baseSysForView.complete.links;
    }
    link.style = LINK;
    link.handles = [];
    link.textHandles = [];
    link.bendPoints = [];
    link.fromSystem = _dss_editor._toolkit.findSystemByName(diagrams, link.from);
    link.toSystem = _dss_editor._toolkit.findSystemByName(diagrams, link.to);
    link.physicFromSystem = null;
    link.physicToSystem = null;
    link.editArea = 0.5;
    if (link.linkType === TYPE_RELATION) {
        link.editArea = 0.1;
    }

    if (!link.fromSystem && links) {
        link.fromSystem = _dss_editor._toolkit.findLinkByName(links, link.from);
    }

   

    //以下是一些方法的初始化

    // 由于from和to保存的是名字，所以在操作的时候需要更新from和to的名字
    link.update = function() {
        this.updateFrom();
        this.updateTo();
    };
    link.updateFrom = function() {
        if (this.fromSystem.style === LINK) {
            this.from = this.fromSystem.name;
        } else {
            this.from = this.fromSystem.getFullName();
        }
    };
    link.updateTo = function() {
        this.to = this.toSystem.getFullName();
    };
    link.getFromSystem = function() {
        if (this.fromSystem.style === STYLE_ROOT) {
            this.fromSystem = null;
        }
        if (this.physicFromSystem != null) {
            return this.physicFromSystem;
        }
        return this.fromSystem;
    };
    link.setFromSystem = function(system) {
        if (this.physicFromSystem != system) {
            this.fromSystem = system;
            this.updateFrom();
            this.physicFromSystem = null;
        }
    };
    link.getToSystem = function() {
        if (this.toSystem.style === STYLE_ROOT) {
            this.toSystem = null;
        }
        if (this.physicToSystem != null) {
            return this.physicToSystem;
        }
        return this.toSystem;
    };
    link.setToSystem = function(system) {
        if (this.physicToSystem != system) {
            this.toSystem = system;
            this.updateTo();
            this.physicToSystem = null;
        }
    };

    link.addLinkFrom = function(l) {
        if (l) {
            this.linkFrom = this.linkFrom || [];
            this.linkFrom.push(l);
        }
        l.setFromSystem(this);
    };
    link.removeLinkFrom = function(link) {
        _dss_editor._toolkit.removeArrayElement(this.linkFrom, link);
    };

    link.addHandle = function(handle) {
        if ( handle instanceof EditTool) {
            this.textHandles.push(handle);
        } else if ( handle instanceof HandleTool) {
            this.handles.push(handle);
        }
    };

    link.clearHandles = function() {
        for (var i in this.textHandles) {
            this.textHandles[i].close();
        }
        this.handles = [];
        this.textHandles = [];
    };

    link.getEditArea = function() {
        var fromPoint = that.getAnchorPoint(this.fromSystem, this.showInfo.fromAngle);
        var toPoint = that.getAnchorPoint(this.toSystem, this.showInfo.toAngle);
        var cp = {};
        //area point
        var area = {
            x : 0,
            y : 0,
            w : 30,
            h : 15
        };
        if (this.bendPoints.length == 1) {
            cp = this.bendPoints[0];
        } else {
            cp.x = fromPoint.x - (fromPoint.x - toPoint.x) * this.editArea;
            cp.y = fromPoint.y - (fromPoint.y - toPoint.y) * this.editArea;
        }
        area.x = cp.x - area.w / 2;
        area.y = cp.y - area.h / 2;
        return area;
    };

    if (link.fromSystem) {
        //	link.fromSystem.addLinkFrom(link);
        link.fromSystem.linkFrom = link.fromSystem.linkFrom || [];
        link.fromSystem.linkFrom.push(link);
    }
    if (link.toSystem) {
        link.toSystem.addLinkTo(link);
    }
    this.layout.apply(link);
    this.updateStatus.apply(link);
};

_link.createLinkSelectionHandle = function(link, canvas) {
    this.createLinkAnchorHandle(link, canvas);
    this.createLinkTextHandle(link, canvas);
};

_link.refreshLinkSelectionHandle = function(canvas) {
    for (var i in canvas.selectionLinks) {
        var link = canvas.selectionLinks[i];
        link.clearHandles();
        this.createLinkSelectionHandle(link, canvas);
    }
};

_link.createLinkTextHandle = function(link, canvas) {
	var getLocation = function() {
		var toolLoc = _dss_editor._toolkit.getToolOffsetLoc(canvas);
		var loc = link.getEditArea();
		toolLoc.x += loc.x;
		toolLoc.y += loc.y;
		return toolLoc;
	};
	var handle = function() {
		var input = new DscTextInput(canvas);
		input.setLocation(getLocation);
		input.initText = link.content;
		input.commiteText = function() {
			var newText = this.getText();
			var command = new ChangeLinkTextCommand(link, newText);
			_dss_editor._command._commandsManager.doCommand(command);
			// link.content = this.getText();
		};
		input.show();
	};
	_dss_editor._model.system.createTextInputHandle(handle, getLocation, link, canvas);
};

_link.createLinkAnchorHandle = function(link, canvas) {
    var srcP = this.getAnchorPoint(link.getFromSystem(), link.showInfo.fromAngle);
    var tarP = this.getAnchorPoint(link.getToSystem(), link.showInfo.toAngle);
    var srcHandle = new HandleTool(link, canvas.entity, srcP);
    var tarHandle = new HandleTool(link, canvas.entity, tarP);
    var srcListener = new HandleListener();
    var tarListener = new HandleListener();

    srcListener.execute = function() {
        canvas.removeLink(link);
    };
    tarListener.execute = function() {
        canvas.removeLink(link);
    };
    tarHandle.addListener(tarListener);
    srcHandle.addListener(srcListener);
    tarHandle.onSelect = function() {
        return LINK_TAR;
    };
    srcHandle.onSelect = function() {
        return LINK_SRC;
    };
    link.addHandle(srcHandle);
    link.addHandle(tarHandle);
};

_link.create = function(type) {
    var link = {
        from : '',
        to : '',
        showInfo : {
            fromAngle : 0,
            toAngle : 0,
            visible : 'yes,no;yes'
        },
        linkType : type,
        content : '',
        isDerived : 0,
        linkFrom : [],
        name : namePrefix + 'LINK_' + new Date().getTime()
    };
    console.log(link.name);
    return link;
};
delete _link;
